package logica;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import logica.persistencia.DiagramaPersistente;
import memento.EstadoGuardable;
import memento.IMemento;
import memento.MementoDiagramaLogico;

// ver tema de entidades repetidas, ver si relacion referencia a entidad del modelo, lo mismo con jerarquia
public abstract class Diagrama implements EstadoGuardable {
	
	private String nombre;
	
	private List<Entidad> entidades = new LinkedList<Entidad>();
	private List<ObjetoDiagrama> objetosDiagramas = new LinkedList<ObjetoDiagrama>();
	
	private List<Diagrama> diagramasHijo = new LinkedList<Diagrama>(); 
	
	
	public Diagrama(String nombre) throws SinNombreException {
		this.setNombre(nombre);
	}
	
	/*
	 * esto para que se agreguen los objetos a sus respectivas listas.
	 * Las entidades tiene una lista especial porque despues necesito
	 * saber que entidades integran el modelo.
	 */
	public void agregarObjetoDiagrama(ObjetoDiagrama objeto) throws EntidadRepetidaException, IdExternoInexistenteException {
		objeto.agregarseAlDiagrama(this);
	}
	
	public void verificarSiSePuedeAgregarObjeto(ObjetoDiagrama objeto) throws IdExternoInexistenteException, EntidadRepetidaException {
		objeto.verificarSiSePuedeAgregarAlDiagrama(this);
	}
	
	void agregarObjetoDiagramaAlDiagrama(ObjetoDiagrama objeto) throws IdExternoInexistenteException, EntidadRepetidaException
	{
		verificarSiSePuedeAgregarObjeto(objeto);
		objeto.setDiagrama(this);
		this.getObjetosDiagramas().add(objeto);
	}
	
	void agregarEntidadAlDiagrama(Entidad entidad) throws IdExternoInexistenteException, EntidadRepetidaException
	{
		this.verificarSiSePuedeAgregarObjeto(entidad);
		entidad.setDiagrama(this);
		this.entidades.add(entidad);
	}

	void verificarSiDependenciasExternasExisten(ObjetoDiagrama objeto) throws IdExternoInexistenteException 
	{
		Iterator<Entidad> iterador = objeto.getReferenciaAEntidadesExternas().iterator();
		
		while (iterador.hasNext())
		{
			Entidad entidadId = iterador.next();
			try 
			{
				verificarSiEntidadRepetida(entidadId);
				throw new IdExternoInexistenteException("No existe en el modelo una entidad fuerte con el nombre: "+entidadId.getNombre());
			} 
			catch (EntidadRepetidaException e) {}
		}
	}

	void verificarSiEntidadRepetida(Entidad entidad) throws EntidadRepetidaException
	{
		Iterator<Entidad> itEntidad = this.getEntidades().iterator();
		
		while (itEntidad.hasNext())
		{
			if (entidad.equals(itEntidad.next()))
				throw new EntidadRepetidaException("No puede existir en el modelo dos entidades con el mismo nombre. Ver: " + entidad);
		}
	}

	public void setNombre(String nombre) throws SinNombreException 
	{
		if (nombre.isEmpty() || nombre == null)
			throw new SinNombreException("El diagrama debe tener un nombre.");
		
		this.nombre = nombre;
	}

	public String getNombre() {
		return nombre;
	}

	public abstract DiagramaPersistente getDiagramaPersistente();

	public List<Entidad> getEntidades(){
		return  entidades;
	}

	//este nombre es confuso porq no incluye a las entidades
	public List<ObjetoDiagrama> getObjetosDiagramas() {
		return objetosDiagramas;
	}

	public List<Diagrama> getDiagramasHijo() {
		return diagramasHijo;
	}

	public DiagramaSecundario crearDiagramaHijo(String nombre) throws SinNombreException
	{
		DiagramaSecundario diagrama = new DiagramaSecundario(nombre, this);
		
		this.diagramasHijo.add(diagrama);
		
		return diagrama;
	}
	
	public String toString() {
		return this.getNombre();
	}

	public void eliminarObjetoDiagramaDelDiagrama(ObjetoDiagrama objetoDiagrama) {
		this.getObjetosDiagramas().remove(objetoDiagrama);
	}

	public void eliminarEntidadDelDiagrama(Entidad entidad) {
		this.getEntidades().remove(entidad);	
	}
	
	@Override
	public IMemento getMementoGenerico() {
		return this.getMementoEspecializado();
	}

	@Override
	public IMemento getMementoEspecializado() {
		return new MementoDiagramaLogico(this);
	}

	@Override
	public void saveMemento(IMemento memento) {
		memento.cargarMemento();
	}
}
